package Sdo.terminalfx;

import com.fasterxml.jackson.databind.ObjectMapper;
import Sdo.terminalfx.annotation.WebkitCall;
import Sdo.terminalfx.config.TerminalConfig;
import Sdo.terminalfx.helper.ThreadHelper;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyIntegerProperty;
import javafx.beans.property.ReadOnlyIntegerWrapper;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker.State;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.layout.Pane;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import netscape.javascript.JSObject;

import java.io.Reader;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;

import org.apache.log4j.Logger;

public class TerminalViewX extends Pane {

	private static Logger logger = Logger.getLogger(Terminal.class);  
	private final WebView webView;
	private final ReadOnlyIntegerWrapper columnsProperty;
	private final ReadOnlyIntegerWrapper rowsProperty;
	private final ObjectProperty<Reader> inputReaderProperty;
	private final ObjectProperty<Reader> errorReaderProperty;
	private TerminalConfig terminalConfig = new TerminalConfig();
	protected final CountDownLatch countDownLatch = new CountDownLatch(1);
	String path;
	String ptext;
	public TerminalViewX() {
		webView = new WebView();
		columnsProperty = new ReadOnlyIntegerWrapper(150);
		rowsProperty = new ReadOnlyIntegerWrapper(10);
		inputReaderProperty = new SimpleObjectProperty<Reader>();
		errorReaderProperty = new SimpleObjectProperty<Reader>();
		inputReaderProperty.addListener(new ChangeListener<Reader>() {
			public void changed(ObservableValue<? extends Reader> observable, Reader oldValue, final Reader newValue) {
				ThreadHelper.start(new Runnable() {
					public void run() {
						
						printReader(newValue);
						
					}
				});
			}
		});

		errorReaderProperty.addListener(new ChangeListener<Reader>() {
			public void changed(ObservableValue<? extends Reader> observable, Reader oldValue, final Reader newValue) {
				ThreadHelper.start(new Runnable() {
					public void run() {
						printReader(newValue);
						
					}
				});
			}
		});

		webView.getEngine().getLoadWorker().stateProperty().addListener(new ChangeListener<State>() {
			public void changed(ObservableValue<? extends State> observable, State oldValue, State newValue) {
				getWindow().setMember("app", TerminalViewX.this);
			}
		});
		webView.prefHeightProperty().bind(heightProperty());
		webView.prefWidthProperty().bind(widthProperty());
		webView.setContextMenuEnabled(false);//设置webview原先的菜单不再显示
		
		try {
			webEngine().load(getClass().getResource("/hterm/hterm.html").toExternalForm());
		} catch (Exception e) {
			// TODO: handle exception
			logger.debug(e.getMessage());
		}
		
		
	}


	
	@WebkitCall(from = "hterm")
	public String getPrefs() {
		try {
			return new ObjectMapper().writeValueAsString(getTerminalConfig());
		} catch(final Exception e) {
			throw new RuntimeException(e);
		}
	}

	public void updatePrefs(TerminalConfig terminalConfig) {
		if(getTerminalConfig().equals(terminalConfig)) {
			return;
		}

		setTerminalConfig(terminalConfig);
		final String prefs = getPrefs();

		ThreadHelper.runActionLater(new Runnable() {
			public void run() {
				try {
					getWindow().call("updatePrefs", prefs);
				} catch(final Exception e) {
					e.printStackTrace();
				}
			}
		}, true);
	}

	@WebkitCall(from = "hterm")
	public void resizeTerminal(int columns, int rows) {
		columnsProperty.set(columns);
		rowsProperty.set(rows);
		
	}

	@WebkitCall
	public void onTerminalInit() {
		ThreadHelper.runActionLater(new Runnable() {
			public void run() {
				getChildren().add(webView);
			}
		}, true);
	}

	@WebkitCall
	/**
	 * Internal use only
	 */
	public void onTerminalReady() {
		ThreadHelper.start(new Runnable() {
			public void run() {
				try {
					
					focusCursor();
					
					countDownLatch.countDown();
				} catch(final Exception e) {
				}
			}
		});
	}

	private void printReader(Reader bufferedReader) {
		try {
			int nRead;
			final char[] data = new char[1 * 1024];

			while((nRead = bufferedReader.read(data, 0, data.length)) != -1) {
				final StringBuilder builder = new StringBuilder(nRead);
				builder.append(data, 0, nRead);
				print(builder.toString());
			
				if(builder.length()>3) {
					String s=builder.substring(builder.lastIndexOf("\n")+1);
					s=s.substring(s.lastIndexOf(":")+1);
//					if(s.contains("~")) {
//						s="~";
//					}else {}

					if(s.contains("#")) {
						s=s.substring(0, s.indexOf('#'));
					}
					if(s.contains("$")) {
						s=s.substring(0, s.indexOf('$'));
					}
					if(s.contains("[")) {
						s=s.substring(0, s.indexOf('[') );
					}
					if(s.contains("]")) {
						s=s.substring(0, s.indexOf(']'));
					}
					if(s.contains("@")) {
						s=s.substring(0, s.indexOf('@') );
					}
					if(s.contains("(")) {
						s=s.substring(0, s.indexOf('(') );
					}
					if(s.contains(")")) {
						s=s.substring(0, s.indexOf(')') );
					}
					if(s.contains("*")) {
						s=s.substring(0, s.indexOf('*'));
					}
					
				
					path=s;
				}
				
			}
		} catch(final Exception e) {
			e.printStackTrace();
		}
	}


	@WebkitCall(from = "hterm")
	public void getStr(String text) {
		final Clipboard clipboard = Clipboard.getSystemClipboard();
		final ClipboardContent clipboardContent = new ClipboardContent();
		clipboardContent.putString(text);
		clipboard.setContent(clipboardContent);
		this.ptext=text;
		

	}
	
	@WebkitCall(from = "hterm")
	public void copy(String text) {
		final Clipboard clipboard = Clipboard.getSystemClipboard();
		final ClipboardContent clipboardContent = new ClipboardContent();
		clipboardContent.putString(text);
		clipboard.setContent(clipboardContent);
	}

	public void onTerminalFxReady(final Runnable onReadyAction) {
		ThreadHelper.start(new Runnable() {
			public void run() {
				ThreadHelper.awaitLatch(countDownLatch);

				if(Objects.nonNull(onReadyAction)) {
					
					ThreadHelper.start(onReadyAction);
				}
			}
		});
	}

	protected void print(final String text) {
		ThreadHelper.awaitLatch(countDownLatch);
		ThreadHelper.runActionLater(new Runnable() {
			public void run() {
				
				getTerminalIO().call("print", text);
				
				
			}
		});

	}

	public void focusCursor() {
		ThreadHelper.runActionLater(new Runnable() {
			public void run() {
				webView.requestFocus();
				getTerminal().call("focus");
				
			}
		}, true);
	}

	private JSObject getTerminal() {
		return (JSObject) webEngine().executeScript("t");
	}

	private JSObject getTerminalIO() {
		return (JSObject) webEngine().executeScript("t.io");
	}

	public JSObject getWindow() {
		return (JSObject) webEngine().executeScript("window");
	}

	private WebEngine webEngine() {
		return webView.getEngine();
	}

	public TerminalConfig getTerminalConfig() {
		if(Objects.isNull(terminalConfig)) {
			terminalConfig = new TerminalConfig();
		}
		return terminalConfig;
	}

	public void setTerminalConfig(TerminalConfig terminalConfig) {
		this.terminalConfig = terminalConfig;
	}

	public ReadOnlyIntegerProperty columnsProperty() {
		return columnsProperty.getReadOnlyProperty();
		
	}

	public int getColumns() {
		return columnsProperty.get();
	}

	public ReadOnlyIntegerProperty rowsProperty() {
		return rowsProperty.getReadOnlyProperty();
	}

	public int getRows() {
		return rowsProperty.get();
	}
	

	
	
	public ObjectProperty<Reader> inputReaderProperty() {
		return inputReaderProperty;
	}

	public Reader getInputReader() {
		return inputReaderProperty.get();
	}

	public void setInputReader(Reader reader) {
		inputReaderProperty.set(reader);
	}

	public ObjectProperty<Reader> errorReaderProperty() {
		return errorReaderProperty;
	}

	public Reader getErrorReader() {
		return errorReaderProperty.get();
	}

	public void setErrorReader(Reader reader) {
		errorReaderProperty.set(reader);
	}

	

}
